
//
// declare format:
//	descriptorS[0,n] type, prifixer[0,n], declare, postfixer[0.n]
//   add "()" to modify the priority of prefixers and postfixers
//

#ifndef __CDECLARE_H__
#define __CDECLARE_H__

#include <vector>
#include <algorithm>

#include "CDIADataType.h"	// CDclFix

#include "miscutil.h"

using namespace std;


class CDescriptor
{
public:
	DWORD Parse(const _TCHAR* pstr, DWORD idEnd=0);
	bool GetDescriptor(_tstring strDescriptor);
	bool IsConst();
	bool IsStatic();
	
private:
	static const TCHAR* m_pDescriptorS[];

private:
	vector<int> m_vDescriptorIDS;
};

struct BaseTypeInfo
{
	const TCHAR* pszName;
	BasicType btBaseType;
	DWORD dwLen; 
};

//
// dia can't get basic type symbol directly!
class CType
{
public:
	CType()
	: m_dwBasicType(INVALID_DWORD)
	{};

public:
	DWORD Parse(const _TCHAR* pstr, DWORD idEnd=0);

	bool IsBasicType()
	{ return (INVALID_DWORD==m_dwBasicType)?false:true; };
	bool GetType(_tstring* pstrType);
	bool GetBasicTypeDiaInfo(BaseTypeInfo* pBscTpDiaInfo);

private:
	static const BaseTypeInfo m_pBaseTypeS[];
	DWORD m_dwBasicType;
	_tstring m_strType;
};


class CFixer
{
public:
	~CFixer(){};

public:
	virtual DWORD Parse(const TCHAR* pstr, DWORD idEnd=0)=0;
	virtual const CDclFix* GetDclFix(){return &m_Fixer;};

public:
	void AppendDclFixStr(_tstring* pstr)
	{
		m_Fixer.AppendDclFixStr(pstr);
	};

protected:
	CDclFix m_Fixer;
};


//	_T("*");
//	_T("&");
//	_T("*const");
class CPrefix: public CFixer
{
public:
	DWORD Parse(const _TCHAR* pstr, DWORD idEnd=0);

public:
	static bool IsPrefix(const TCHAR* pstr);
};

class CPostfix: public CFixer
{
public:
	DWORD Parse(const TCHAR* pstr, DWORD idEnd=0);

public:
	static bool IsPostfix(const TCHAR* pstr);
};

//
//1 !! not implement now !!
class CFunPtr: public CFixer
{
public:
	DWORD Parse(const TCHAR* pstr, DWORD idEnd=0){return false;};

public:
	static bool IsFunPtr(const TCHAR* pstr)
	{
		DWORD id=EatWhite(pstr);
		if(_T('(')!=pstr[id])
		{
			return false;
		}
		id++;

		id+=EatWhite(pstr+id);
		if(_T('*')!=pstr[id])
		{
			return false;
		}

		const TCHAR* pEnd=find_if(pstr+id, pstr+_tcslen(pstr+id)+id, FnObFindPairEnd<const TCHAR>(_T('('), _T(')')));
		if(pEnd==pstr+_tcslen(pstr+id))
		{
			return false;
		}

		id=pEnd-pstr+1;
		id+=EatWhite(pstr+id);
		if(_T('(')!=pstr[id])
		{
			return false;
		}
		id++;
		
		pEnd=find_if(pstr+id, pstr+_tcslen(pstr+id), FnObFindPairEnd<TCHAR>(_T('('), _T(')')));
		if(pEnd==(pstr+_tcslen(pstr+id)+id))
		{
			return false;
		}
		
		return true;
	}

};


//
// add "()" to modify the "priority" of prefix and postfix
class CPriorityModifier
{
public:
	static bool IsPriorityModifier(const TCHAR* pstr);
	static DWORD FindEnd(const TCHAR* pstr, DWORD idEnd=0);
};

//
// the name of variable in declaration
class CDeclarator
{
public:
	DWORD Parse(const TCHAR* pstr, DWORD idEnd=0);

	bool IsValid()
	{return (0==m_Declarator.size())?false:true;};

	bool GetDeclarator(_tstring* pDeclarator);

private:
	_tstring m_Declarator;
};


class CDeclare
{
public:
	CDeclare(const TCHAR* pDeclare)
	:m_strDeclare(pDeclare)
	{};

	~CDeclare();

public:
	bool Parse();

	// pvpFixerS contain the "new" generated objects, remember to "delete" them
	bool PaseDeclarator(const TCHAR* pDeclarator, DWORD idEnd,  vector<CFixer*>* pvpFixerS);
	
public:	
	bool GetType(_tstring* pstrType){return m_Type.GetType( pstrType);};
	bool IsDiaBaseType(){return m_Type.IsBasicType();};
	bool GetBasicTypeDiaInfo(BaseTypeInfo* pBscTpDiaInfo){return m_Type.GetBasicTypeDiaInfo(pBscTpDiaInfo);};
	
	bool GetDeclarator(_tstring* pDeclarator){return m_Declarator.GetDeclarator(pDeclarator);};

	bool GetDclFixStr(_tstring* pstrFix);
	VOID GetDclFixS(vector<CDclFix>* pvectDclFixS);

	bool GetDeclare(_tstring* pstrDclr);

private:
	CDescriptor m_Discriptor;
	CType m_Type;
	vector<CFixer*> m_vpFixerS;
	CDeclarator m_Declarator;

private:
	_tstring m_strDeclare;
};

#endif	//#ifndef __CDECLARE_H__


